package infb.util;

import java.util.*;
import javax.servlet.http.*;


public class Paginador {

    /* Atributos de clase para manejar la configuracion
     * de la clase Paginador
     */
    public static String VAR_PAGINACION="pag";
    public static int REGISTROS_POR_PAGINA=10;
    public static int MAX_ENLACES=10;
    public static boolean PROPAGAR=true;
    public static String SEPARADOR="|";
    public static String TEXTO_ANTERIOR="Anterior";
    public static String TEXTO_SIGUIENTE="Siguiente";

    private List listaRegistros_;
    private List listaPaginada_;
    private String enlace_;
    private HttpServletRequest peticion_;
    private String navegacion_;
    private int [] informacion_;

    /*
     * Constructor: requiere de la lista con los resultados a paginar
     * y del objeto HttpServletRequest que representa la peticion del
     * cliente
     */
    public Paginador(List listaRegistros,HttpServletRequest peticion) {
        this.listaRegistros_=listaRegistros;
        this.enlace_=peticion.getRequestURL().toString();
        this.peticion_=peticion;
        this.informacion_=new int[5];
        this.listaPaginada_=this.paginar();
    }

    public int[] getInformacionPaginacion(){
        return this.informacion_;
    }

    /*
     * Funcion que devuelve un objeto String con el vector de navegacion (a href=...)
     * construido correctamente
     */
    public String getNavegacion() {
        return this.navegacion_;
    }

    /* Funcion que devuelve el objeto List con los registros paginados
     * (si no se encontraron resultados en la busqueda devolvera NULL)
     */
    public List getResultadosPaginados() {
        return this.listaPaginada_;
    }

    /*
     * Funcion que encapsula en un objeto String todo el resultado
     * de haber llevado a cabo todo el mecanismo de paginacion
     */
    public String getMetaInformacion() {
        String meta="Resultados: "+this.informacion_[0]+", Mostrados del "+this.informacion_[3]+
                    " al "+this.informacion_[4];

        return meta;
    }

    /*
     * Metodo principal para realizar el mecanismo de paginacion invocado implicitamente
     * desde el constructor de la clase
     * Parametros: Ninguno
     * Devuelve: Un objeto List con los registros paginados o bien NULL si no se
     *           encontraron resultados en la consulta
     */
    public List paginar() {
        // Comprobacion basica
        if(this.listaRegistros_==null || this.listaRegistros_.size()==0){
            return null;
        }

        int numeroRegistros,numeroPaginas,numeroRegistroInicio,numeroRegistroFin,
            paginaActual,paginaURL,desdePagina,hastaPagina,intervalo;
        List navegacionTemp;
        String urlEnlace;
        Enumeration parametrosURL;

        numeroRegistros=this.listaRegistros_.size();
        numeroPaginas=(int)Math.ceil((double)numeroRegistros/(double)REGISTROS_POR_PAGINA);

        // Establecemos la pagina actual
        if(peticion_.getParameter(VAR_PAGINACION)==null){
            paginaActual=1;
        }else{
            try{
                paginaActual=new Integer(peticion_.getParameter(VAR_PAGINACION)).intValue();

                // Realizamos un pequeño control sobre el valor contenido en la variable URL
                if(paginaActual>numeroPaginas){
                    paginaActual=numeroPaginas;
                }else if(paginaActual<=0){
                    paginaActual=1;
                }
            }catch(NumberFormatException nfe){
                paginaActual=1;
            }
        }

        // Generamos el vector de navegacion temporal
        navegacionTemp=new Vector();
        parametrosURL=this.peticion_.getParameterNames();
        urlEnlace=this.enlace_+"?";
        if(PROPAGAR){
            while(parametrosURL.hasMoreElements()){
                String parametro = (String)parametrosURL.nextElement();
                if(!parametro.equalsIgnoreCase(VAR_PAGINACION)){
                    urlEnlace+=parametro+"="+peticion_.getParameter(parametro)+"&";
                }
            }
        }

        if(paginaActual!=1){
            paginaURL=paginaActual-1;
            navegacionTemp.add("<a href='"+urlEnlace+VAR_PAGINACION+"="+paginaURL+"'>"+TEXTO_ANTERIOR+"</a>");
        }

        if(MAX_ENLACES<0){
            desdePagina=1;
            hastaPagina=numeroPaginas;
        }else{
            intervalo=(MAX_ENLACES/2)-1;
            desdePagina=paginaActual-intervalo;
            hastaPagina=paginaActual+intervalo;
            if(desdePagina<1){
                hastaPagina-=(desdePagina-1);
                desdePagina=1;
            }
            if(hastaPagina>numeroPaginas){
                desdePagina-=(hastaPagina-numeroPaginas);
                hastaPagina=numeroPaginas;
                if(desdePagina<1){
                    desdePagina=1;
                }
            }
        }

        for(int i=desdePagina;i<=hastaPagina;i++){
            if(i==paginaActual){
                navegacionTemp.add("<span>["+i+"]</span>");
            }else{
                navegacionTemp.add("<a href='"+urlEnlace+VAR_PAGINACION+"="+i+"'>"+i+"</a>");
            }
        }

        if(paginaActual<numeroPaginas){
            paginaURL=paginaActual+1;
            navegacionTemp.add("<a href='"+urlEnlace+VAR_PAGINACION+"="+paginaURL+"'>"+TEXTO_SIGUIENTE+"</a>");
        }

        // Generamos el vector de navegacion definitivo
        this.navegacion_=new String();
        Iterator it=navegacionTemp.iterator();
        while(it.hasNext()){
            this.navegacion_+=(String)it.next();
            if(it.hasNext()){
                this.navegacion_+=SEPARADOR;
            }
        }

       // Obtenemos los registros que se mostraran en la pagina actual
       numeroRegistroInicio=(paginaActual-1)*REGISTROS_POR_PAGINA;
       numeroRegistroFin=numeroRegistroInicio+REGISTROS_POR_PAGINA;
       if(numeroRegistroFin>numeroRegistros){
           numeroRegistroFin=numeroRegistros;
       }
       List registrosPaginados=new Vector();
       for(int i=numeroRegistroInicio;i<numeroRegistroFin;i++){
           registrosPaginados.add(this.listaRegistros_.get(i));
       }

       // Incorporamos la informacion de la paginacion
       this.informacion_[0]=numeroRegistros;
       this.informacion_[1]=numeroPaginas;
       this.informacion_[2]=REGISTROS_POR_PAGINA;
       numeroRegistroInicio++;
       this.informacion_[3]=numeroRegistroInicio>numeroRegistros?numeroRegistros:numeroRegistroInicio;
       this.informacion_[4]=numeroRegistroFin;

       // Devolvemos el resultado
       return registrosPaginados.size()>0?registrosPaginados:null;
    }

}